package com.sjp.demo.netty.rpc.registry;

import com.sjp.demo.netty.rpc.protocol.InvokerProtocol;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class RegistryHandler extends ChannelInboundHandlerAdapter {

    //1、 根据一个包名将所有符合的class全部扫描出来，放到一个容器中
    //2、 给每一个对应的class起一个唯一名字，作为服务名称，保存到一个容器中
    //3、客户端连接过来后，获取协议内容
    //4、去注册好的容器中找到符合条件的服务
    //5、通过远程调用Provider得到返回结果，返回给客户端


    private List<String> classNames = new ArrayList<>();
    private Map<String, Object> registryMap = new ConcurrentHashMap<>();

    public RegistryHandler() {
        scanClass("com.sjp.demo.netty.rpc.provider");
        doRegistry();
    }

    private void doRegistry() {
        if (classNames.isEmpty()) {
            return;
        }
        for (String className : classNames) {
            try {
                Class<?> clazz = Class.forName(className);
                Class<?> i = clazz.getInterfaces()[0];
                String serviceName = i.getName();

                registryMap.put(serviceName, clazz.newInstance());

            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    private void scanClass(String packageName) {
        URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.", "/"));
        File classPath = new File(url.getFile());
        for (File file : classPath.listFiles()) {
            if (file.isDirectory()) {
                scanClass(packageName + "." + file.getName());
            } else {
                classNames.add(packageName + "." + file.getName().replace(".class", ""));
            }
        }


    }

    /**
     * 有客户端连上的时候执行
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("接收到请求：" + msg);
        Object result = new Object();
        InvokerProtocol request = (InvokerProtocol) msg;
        if (registryMap.containsKey(request.getClassName())) {
            Object service = registryMap.get(request.getClassName());
            Method method = service.getClass().getMethod(request.getMethodName(), request.getParams());
            result = method.invoke(service, request.getValues());
        }
        System.out.println("返回值：" + result);
        ctx.write(result);
        ctx.flush();
        ctx.close();
    }

    /**
     * 连接发生异常的时候执行
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    }
}
